﻿using Ionic.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DnaServiceLib
{
    public class FileLoader
    {
        public bool AllowZipFiles { get; set; }
        public bool SkipLinesStartingWithPoundSign { get; set; }

        public List<string> AllowedImportExtensionList { get; set; }
        public List<string> AllowedZipExtensionList { get; set; }

        public FileLoader(string[] allowedImportExtensions, bool allowZipFiles = false, string[] allowedZipExtensions = null, bool skipLinesStartingWithPoundSign = false)
        {
            if (allowedImportExtensions!=null)
                AllowedImportExtensionList = allowedImportExtensions.ToList();
            else
                AllowedImportExtensionList = new List<string>();
            AllowZipFiles = allowZipFiles;
            if (allowedZipExtensions != null)
                AllowedZipExtensionList = allowedZipExtensions.ToList();
            else
                AllowedZipExtensionList = new List<string>();
            SkipLinesStartingWithPoundSign = skipLinesStartingWithPoundSign;
        }

        #region validate load settings
        private void ValidateSettings()
        {
            if (AllowedImportExtensionList.Count() == 0)
                throw new FileLoaderException("No Import Extensions have been specified.");

            if (AllowZipFiles && AllowZipFiles == true && AllowedZipExtensionList.Count() == 0)
                throw new FileLoaderException("AllowZipFiles has been enabled but no valid extensions have been specified.");
        }

        #endregion
        public MemoryStream LoadToMemoryStream(string fileName)
        {

            string fileExtension = fileName.Split('.').LastOrDefault();

            using (MemoryStream inputMemoryStream = new MemoryStream())
            {


                if (AllowedZipExtensionList.Any(a => a == fileExtension)) //This uses linq to see if the allowedZipExtensions includes the extension
                {
                    if (fileExtension == "gz")
                    {
                        try
                        {
                            GZipStream uncompressed = new GZipStream(new FileStream(fileName, FileMode.Open), CompressionMode.Decompress);
                            uncompressed.CopyTo(inputMemoryStream);
                            uncompressed.Close();
                        }
                        catch (Exception ex)
                        {
                            throw new FileLoaderException(String.Format("Could not read extract gz format - {0}", ex.Message));
                        }
                    }
                    else
                    {
                        try
                        {
                            using (ZipFile zip = ZipFile.Read(fileName))
                            {
                                if (zip.Count == 0)
                                {
                                    throw new FileLoaderException("Zip does not contain any files");
                                }
                                else
                                {
                                    bool foundMatchingExtension = false;
                                    foreach (ZipEntry zipEntry in zip)
                                    {
                                        if (foundMatchingExtension == false)
                                        {
                                            string zipEntryExtension = zipEntry.FileName.Split('.').LastOrDefault();
                                            if (AllowedImportExtensionList.Any(a => a == zipEntryExtension))
                                            {
                                                zipEntry.Extract(inputMemoryStream);
                                                foundMatchingExtension = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (!foundMatchingExtension)
                                    {
                                        throw new FileLoaderException("Zip supplied did not include a file with any of the specified extensions.");
                                    }
                                }
                            }
                        }
                        catch (FileLoaderException ex)
                        {
                            throw ex;
                        }
                        catch (Exception ex)
                        {
                            throw new FileLoaderException(ex.Message);
                        }
                    }
                }
                else if (AllowedImportExtensionList.Any(a => a == fileExtension))
                {
                    FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                    byte[] bytes = new byte[file.Length];
                    file.Read(bytes, 0, (int)file.Length);
                    inputMemoryStream.Write(bytes, 0, (int)file.Length);
                    file.Close();
                }
                else
                {
                    throw new FileLoaderException("File extension did not match an allowed extension");
                }

                //File should now be in a memorystream do any manual processing needed to build the output memorystream
                if (!SkipLinesStartingWithPoundSign)
                {
                    MemoryStream outputMemoryStream = new MemoryStream(inputMemoryStream.ToArray());
                    return outputMemoryStream;
                }
                else
                {
                    string line;
                    StringBuilder sb = new StringBuilder();
                    inputMemoryStream.Position = 0;
                    StreamReader file = new StreamReader(inputMemoryStream);
                    while ((line = file.ReadLine()) != null)
                    {
                        if (line.Length > 0 && line[0] != '#')
                            sb.AppendLine(line);
                    }
                    MemoryStream outputMemoryStream = new MemoryStream();
                    outputMemoryStream.Write(Encoding.ASCII.GetBytes(sb.ToString()), 0, sb.ToString().Length);
                    return outputMemoryStream;
                }

            }
            


        }

    }
}
